import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import {ShadowMapViewer } from 'three/examples/jsm/utils/ShadowMapViewer'
let renderer, camera, scene
let axesHelper
let controls
let dirLight, spotLight
let ground, torusKnot, cube
let Clock = new THREE.Clock()
let dirLightShadowMapViewer,spotLightShadowMapViewer





initRenderer()
initCamera()
initScene()
initAxesHelper()
initLights()
initMeshes()
initControls()
enableShadow()
initCameraHelper()
initShadowMapViewer()
animate()


window.addEventListener('resize', function () {
    camera.aspect = window.innerWidth / window.innerHeight
    camera.updateProjectionMatrix()
    renderer.setSize(window.innerWidth, window.innerHeight)

    resiezeShadowMapViewers()
    dirLightShadowMapViewer.updateForWindowResize()
    spotLightShadowMapViewer.updateForWindowResize()
})


function initRenderer() {
    renderer = new THREE.WebGLRenderer()
    renderer.setPixelRatio(window.devicePixelRatio)
    renderer.setSize(window.innerWidth, window.innerHeight)
    document.body.appendChild(renderer.domElement)
}

function initCamera() {
    camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000)
    camera.position.set(0,15,35)
}

function initScene(params) {
    scene = new THREE.Scene()
    // scene.background = new THREE.Color(0x888888)
}

function initAxesHelper(params) {
    axesHelper = new THREE.AxesHelper(3)
    scene.add(axesHelper)
}
function initLights(params) {
    // 环境光
    scene.add(new THREE.AmbientLight(0x404040))
    //点光源
    spotLight = new THREE.SpotLight(0xffffff)
    spotLight.name = "Spot light"
    spotLight.angle = Math.PI / 5
    spotLight.penumbra = 0.3
    spotLight.position.set(10, 10, 5)
    scene.add(spotLight)

    //平行光
    dirLight = new THREE.DirectionalLight(0xffffff, 1)
    dirLight.name = "Dir light";
    dirLight.position.set(0, 10, 0)
    scene.add(dirLight)
}
//创建物体
function initMeshes(params) {
    /* torus */
    let geometry = new THREE.TorusKnotGeometry(25, 8, 200, 20)
    let material = new THREE.MeshPhongMaterial({
        color: 0xff0000,
        shininess: 150,
        specular: 0x222222
    });
    torusKnot = new THREE.Mesh(geometry, material)
    torusKnot.scale.multiplyScalar(1 / 18)
    torusKnot.position.y = 3
    scene.add(torusKnot)

    /* cube */
    geometry = new THREE.BoxGeometry(3, 3, 3)
    cube = new THREE.Mesh(geometry, material)
    cube.position.set(8,3,8)
    scene.add(cube)

    /* ground */
    geometry = new THREE.BoxGeometry(10, 0.15, 10);
    material = new THREE.MeshPhongMaterial({
        color: 0xa0adaf,
        shininess: 150,
        specular: 0x111111
    });
    ground = new THREE.Mesh(geometry, material);
    ground.scale.multiplyScalar(3)
    scene.add(ground)
}

function enableShadow(params) {
    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.BasicShadowMap;
    
    spotLight.castShadow = true;
    dirLight.castShadow = true;

    torusKnot.castShadow = true;
    torusKnot.receiveShadow = true;
    
    cube.castShadow = true;
    cube.receiveShadow = true;

    ground.castShadow = false;
    ground.receiveShadow = true;
}

//辅助器
function initCameraHelper() {
    spotLight.shadow.camera.near = 8
    spotLight.shadow.camera.far = 30
    spotLight.shadow.mapSize.width = 1024
    spotLight.shadow.mapSize.height = 1024
    scene.add(new THREE.CameraHelper(spotLight.shadow.camera))

    dirLight.shadow.camera.near = 1
    dirLight.shadow.camera.far = 10
    dirLight.shadow.camera.right = 15
    dirLight.shadow.camera.left = -15
    dirLight.shadow.camera.top = 15
    dirLight.shadow.camera.bottom = -15
    scene.add(new THREE.CameraHelper(dirLight.shadow.camera))
}

function  initShadowMapViewer(params) {
    dirLightShadowMapViewer = new ShadowMapViewer(dirLight)
    spotLightShadowMapViewer = new ShadowMapViewer(spotLight)
    resiezeShadowMapViewers()
}
function resiezeShadowMapViewers(params) {
    const size = window.innerWidth * 0.2
    dirLightShadowMapViewer.position.x = 10
    dirLightShadowMapViewer.position.y = 10
    dirLightShadowMapViewer.size.width = size
    dirLightShadowMapViewer.size.height = size
    dirLightShadowMapViewer.update()

    spotLightShadowMapViewer.size.set(size, size)
    spotLightShadowMapViewer.position.set(size + 20, 10);
}


function initControls(params) {

    controls = new OrbitControls(camera, renderer.domElement)
    controls.target.set(0, 1, 0)
    controls.update()
}

function animate(params) {
    requestAnimationFrame(animate)

    render()
}

function render(params) {
    const delta = Clock.getDelta()
    renderer.render(scene, camera)
    torusKnot.rotation.x += 0.25 * delta
    torusKnot.rotation.y += 2 * delta
    torusKnot.rotation.z += 1 * delta
    
    cube.rotation.x += 0.25 * delta
    cube.rotation.y += 2 * delta
    cube.rotation.z += 1*delta
    
    dirLightShadowMapViewer.render(renderer)
    spotLightShadowMapViewer.render(renderer)
    
    
}
